﻿using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using eCommerce.SagePay.Classes;

namespace eCommerce.SagePay
{
    public class HttpRequestHelper
    {
        /// <summary>
        /// Builds the request.
        /// </summary>
        /// <param name="basketDetails">The basket details.</param>
        /// <param name="billingDetails">The billing details.</param>
        /// <param name="deliveryDetails">The delivery details.</param>
        /// <param name="vendorTxCode">The vendor tx code.</param>
        /// <returns></returns>
        public string BuildRequest(BasketDetails basketDetails, Billing billingDetails, Delivery deliveryDetails, string vendorTxCode)
        {
            const string protocol = "2.23";
            const string transactionType = "PAYMENT";
            const string vendorName = "2beknowndevsite";

            string postString = "VPSProtocol=" + protocol;
            postString += "&TxType=" + transactionType;
            postString += "&Vendor=" + vendorName;
            postString += "&VendorTxCode=" + vendorTxCode;

            // Basket Details
            postString += "&Amount=" + basketDetails.Amount;
            postString += "&Currency=" + basketDetails.Currency;
            postString += "&Description=" + HttpUtility.HtmlEncode(basketDetails.Description); // Any description we want
            postString += "&CardHolder=" + basketDetails.CardHolder;
            postString += "&CardNumber=" + basketDetails.CardNumber;
            postString += "&StartDate=" + basketDetails.StartDate;
            postString += "&ExpiryDate=" + basketDetails.ExpiryDate;
            postString += "&CardType=" + basketDetails.CardType;
            postString += "&CV2=" + basketDetails.CV2;
            

            // If card has an issue number
            if (basketDetails.IssueNumber > 0) { postString += "&IssueNumber=" + basketDetails.IssueNumber; }

            // Billing Details
            postString += "&BillingSurname=" + billingDetails.Surname;
            postString += "&BillingFirstnames=" + billingDetails.FirstNames;
            postString += "&BillingAddress1=" + billingDetails.Address1;
            postString += "&BillingAddress2=" + billingDetails.Address2;
            postString += "&BillingCity=" + billingDetails.City;
            postString += "&BillingPostCode=" + billingDetails.PostCode;
            postString += "&BillingCountry=" + billingDetails.Country;
            postString += "&BillingState=" + billingDetails.State;
            postString += "&BillingPhone=" + billingDetails.Phone;

            // Delivery Details
            postString += "&DeliverySurname=" + deliveryDetails.Surname;
            postString += "&DeliveryFirstnames=" + deliveryDetails.FirstNames;
            postString += "&DeliveryAddress1=" + deliveryDetails.Address1;
            postString += "&DeliveryAddress2=" + deliveryDetails.Address2;
            postString += "&DeliveryCity=" + deliveryDetails.City;
            postString += "&DeliveryPostCode=" + deliveryDetails.PostCode;
            postString += "&DeliveryCountry=" + deliveryDetails.Country;
            postString += "&DeliveryState=" + deliveryDetails.State;
            postString += "&DeliveryPhone=" + deliveryDetails.Phone;
            postString += "&CustomerEMail=" + deliveryDetails.Email;
            postString += "&Basket=" + deliveryDetails.Basket; // TODO : THIS NEEDS TO BE FILLED IN
            postString += "&ClientIPAddress=" + deliveryDetails.IpAddress;

            // Settings
            postString += "&Apply3DSecure=0"; // We need to confirm this
            postString += "&AccountType=E";
            postString += "&ApplyAVSCV2=1";


            return postString;
        }

        /// <summary>
        /// Sends the request.
        /// </summary>
        /// <param name="basketDetails">The basket details.</param>
        /// <param name="billingDetails">The billing details.</param>
        /// <param name="deliveryDetails">The delivery details.</param>
        public SagePayResponse SendRequest(BasketDetails basketDetails, Billing billingDetails, Delivery deliveryDetails)
        {
            try
            {
                string vendorTxCode = "2beknowndevsite-" + DateTime.Now.Ticks;
                string responseString = PostRequest(vendorTxCode,
                                                    BuildRequest(basketDetails, billingDetails, deliveryDetails,
                                                                 vendorTxCode), "purchase");

                string status = SagePayHelper.FindField("Status", responseString);
                string statusDetail = SagePayHelper.FindField("StatusDetail", responseString);

                return new SagePayResponse
                           {
                               Status = status,
                               StatusDetails = statusDetail,
                               SecurityKey = SagePayHelper.FindField("SecurityKey", responseString),
                               VPSTxId = SagePayHelper.FindField("VPSTxId", responseString),
                               TxAuthNo = SagePayHelper.FindField("TxAuthNo", responseString),
                               ThreeDSecureStatus = SagePayHelper.FindField("3DSecureStatus", responseString),
                               VendorTxCode = vendorTxCode,
                               AVSCV2 = SagePayHelper.FindField("AVSCV2", responseString),
                               AddressResult = SagePayHelper.FindField("AddressResult", responseString),
                               PostCodeResult = SagePayHelper.FindField("PostCodeResult", responseString),
                               CV2Result = SagePayHelper.FindField("CV2Result", responseString),
                               ACSUrl = SagePayHelper.FindField("ACSURL", responseString),
                               MD = SagePayHelper.FindField("MD", responseString),
                               PAReq = SagePayHelper.FindField("PAReq", responseString),
                               FullStatus = SagePayHelper.GetFullStatusDetails(status, statusDetail)
                           };

            }
            catch (Exception exception)
            {
                return new SagePayResponse
                           {
                               Status = "ERROR",
                               StatusDetails = exception.Message
                           };
            }
        }

        /// <summary>
        /// Sends the request.
        /// </summary>
        /// <param name="vendorTxCode">The vendor tx code.</param>
        /// <param name="buildRequest">The build request.</param>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public string PostRequest(string vendorTxCode,string buildRequest,string type)
        {
            const string connectTo = "SIMULATOR";

            UTF8Encoding utfEncode = new UTF8Encoding();
            Uri objUri = new Uri(SagePayHelper.SystemUrl(connectTo, type));

            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(objUri);

            request.KeepAlive = false;
            request.Method = "POST";

            request.ContentType = "application/x-www-form-urlencoded";
            byte[] arrRequest =
                utfEncode.GetBytes(buildRequest);
            request.ContentLength = arrRequest.Length;

            Stream objStreamReq = request.GetRequestStream();
            objStreamReq.Write(arrRequest, 0, arrRequest.Length);
            objStreamReq.Close();

            // Get response
            WebResponse response = request.GetResponse();
            StreamReader objStreamRes = new StreamReader(response.GetResponseStream(), Encoding.ASCII);

            string responseString = objStreamRes.ReadToEnd();
            objStreamRes.Close();
            return responseString;
        }
    }
}


